home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 1 / PC Actual CD 01.iso / share / dos / utilidad / comptest.arj / CCNEW.ASM < prev    next >
Encoding:
Assembly Source File  |  1994-08-26  |  42.7 KB  |  779 lines

  1.              PAGE    ,120
  2.  
  3.             .386p                        ; 80386 code will be used
  4.             .387                         ; need coprocessor, too
  5.  
  6. JMPS        EQU     <JMP SHORT>          ; declare jumps as short
  7. JES         EQU     <JE  SHORT>          ;  since near jumps (+/- 32K)
  8. JBS         EQU     <JB  SHORT>          ;   are default in 386 mode
  9. JNZS        EQU     <JNZ SHORT>          ;    and these cannot execute
  10. JCS         EQU     <JC  SHORT>          ;     on the older CPUs
  11. JZS         EQU     <JZ  SHORT>
  12. JNES        EQU     <JNE SHORT>
  13. JAES        EQU     <JAE SHORT>
  14. JBES        EQU     <JBE SHORT>
  15. JAS         EQU     <JA  SHORT>
  16. CPUID       EQU     <DB  00Fh, 0A2h>
  17.  
  18. cpu_i8088   EQU     1
  19. cpu_i8086   EQU     2
  20. cpu_V20     EQU     3
  21. cpu_V30     EQU     4
  22. cpu_i188    EQU     5
  23. cpu_i186    EQU     6
  24. cpu_i286    EQU     7
  25. cpu_i386    EQU     8
  26. cpu_i386sx  EQU     9
  27. cpu_ct38600 EQU     10
  28. cpu_ct38600sx   EQU 11
  29. cpu_486dlc  EQU     12
  30. cpu_486slc  EQU     13
  31. cpu_RapidCAD EQU    14
  32. cpu_i486    EQU     15
  33. cpu_i486SX  EQU     16
  34. cpu_iDX4    EQU     17
  35. cpu_pentium EQU     18
  36. cpu_ovrdrv  EQU     19
  37.  
  38. ndp_NoCopro EQU     0
  39. ndp_Emul    EQU     1
  40. ndp_i8087   EQU     2
  41. ndp_i80C187 EQU     3
  42. ndp_i80287  EQU     4
  43. ndp_i287XL  EQU     5
  44. ndp_i387    EQU     6
  45. ndp_i387sx  EQU     7
  46. ndp_2C87    EQU     8
  47. ndp_3C87    EQU    10
  48. ndp_3C87sx  EQU    11
  49. ndp_82S87   EQU    12
  50. ndp_83D87   EQU    14
  51. ndp_83S87   EQU    15
  52. ndp_83C87   EQU    16
  53. ndp_83C87s  EQU    17
  54. ndp_38700   EQU    18
  55. ndp_38700sx EQU    19
  56. ndp_i387DX  EQU    20
  57. ndp_RapidCAD EQU   21
  58. ndp_i486    EQU    22
  59. ndp_82S87p  EQU    23
  60. ndp_387plus EQU    25
  61. ndp_83S87p  EQU    26
  62. ndp_emc87   EQU    27
  63. ndp_pentium EQU    28
  64. ndp_iDX4    EQU    29
  65. ndp_ovrdrv  EQU    30
  66.  
  67.  
  68. STRT_TIM    MACRO
  69.             MOV     AL, 0B4h             ; timer 2 is
  70.             OUT     43h, AL              ;  programmed as a rate generator
  71.             XOR     AL, AL               ; load zero
  72.             OUT     42h, AL              ; reset
  73.             OUT     42h, AL              ;  timer 2
  74.             ENDM
  75.  
  76. STOP_TIM    MACRO
  77.             MOV     AL, 80h              ; timer 2
  78.             OUT     43h, AL              ;  immediately latched
  79.             IN      AL, 42h              ; read LSB
  80.             MOV     BL, AL               ; save LSB
  81.             IN      AL, 42h              ; read MSB
  82.             MOV     BH, AL               ; save MSB
  83.             NEG     BX                   ; negate for timer count
  84.             ENDM
  85.  
  86.  
  87.  
  88. CODE        SEGMENT BYTE USE16 PUBLIC 'CODE'
  89.  
  90.             ASSUME  CS:CODE
  91.  
  92.             PUBLIC  SpeedTest
  93.  
  94.                                          ; declare parameters
  95.  
  96. Debug_Flag  EQU     [BP+24]              ; <> 0, if debugging output desired
  97. Ext_Flag    EQU     [BP+22]              ; zero, if no extended memory
  98. EMS_Flag    EQU     [BP+20]              ; zero, if no expanded memory
  99. BufferPtr   EQU     [BP+16]              ; buffer for EMS u. EXT test
  100. EMS_Base    EQU     [BP+12]              ; address of EMS-frame
  101. ScreenPtr   EQU     [BP+8]               ; start address of video memory
  102. ResultPtr   EQU     [BP+4]               ; pointer to result struct
  103.  
  104.  
  105.                                          ; declare local variables
  106.  
  107. Stat        EQU     [BP-2]               ; mem for 80x87 status word
  108. Ctrl        EQU     [BP-4]               ; mem for 80x87 control word
  109. GDT         EQU     [BP-52]              ; mem for global descriptor table
  110. SystemStat  EQU     [BP-53]              ; mem for system status
  111. SaveCtrl    EQU     [BP-55]              ; original 80x87 control word
  112.  
  113.  
  114.                                          ; declare result record
  115. CPU_NDP_TYP EQU     [SI]
  116. AAMTime     EQU     [SI+2]
  117. MovEvenTime EQU     [SI+6]
  118. BIOSWrTime  EQU     [SI+8]
  119. MovByteTime EQU     [SI+10]
  120. MovEMSTime  EQU     [SI+12]
  121. MovExtTime  EQU     [SI+14]
  122. ScrFillTime EQU     [SI+16]
  123. Dummy2      EQU     [SI+18]
  124. i87Time     EQU     [SI+20]
  125. i287Time    EQU     [SI+22]
  126. MovDblTime  EQU     [SI+24]
  127.  
  128. SpeedTest   PROC    NEAR
  129.             PUSH    BP                   ; save caller's frame pointer
  130.             MOV     BP, SP               ; make new frame pointer
  131.             SUB     SP, 55               ; alloc mem for local variables
  132.             PUSH    DS                   ; save Turbo Pascal's data segment
  133.             PUSHF                        ; save original flag setting
  134.  
  135. $inittimer: CLI                          ; disable interrupts
  136.             CLD                          ; auto increment for string operations
  137.             IN      AL, 61h              ; port B - system control
  138.             MOV     [SystemStat], AL     ; save system status
  139.             AND     AL, 11111101b        ; clear speaker bit (disable speaker)
  140.             OR      AL, 1                ; turn on bit for timer 2 (enable it)
  141.             CMP     AL, [SystemStat]     ; system already configured correctly ?
  142.             JES     $aam                 ; no need to configure it
  143.             OUT     61h, AL              ; reconfigure system (tmr 2 on,spk off)
  144.  
  145. $aam:       CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  146.             JNZS    $aam1                ; no
  147.             MOV     AH, 9                ; #9, print string
  148.             PUSH    CS                   ; load
  149.             POP     DS                   ;  address of
  150.             MOV     DX, OFFSET CS:$dbg2  ;   debugging message
  151.             INT     21h                  ; call DOS, print debugging message
  152.             JMPS    $aam1                ; skip message text
  153.  
  154. $dbg2       DB      'About to perform AAM speed test', 0Dh, 0Ah ,'$'
  155.  
  156. $aam1:      STRT_TIM                     ; start timer 2
  157.             REPT    200
  158.             AAM                          ; execute 200 AAMs
  159.             ENDM
  160.             STOP_TIM                     ; elapsed time of timer 2 in BX
  161.             LDS     SI, ResultPtr        ; pointer to result struct
  162.             MOV     [AAMTime], BX        ; save time for AAMs
  163.  
  164. $begin_test:CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  165.             JNZS    $cpu_ndptst          ; nope
  166.             MOV     AH, 9                ; #9, print string
  167.             PUSH    CS                   ; load
  168.             POP     DS                   ;  address of
  169.             MOV     DX, OFFSET CS:$dbg1  ;   debugging message
  170.             INT     21h                  ; call DOS, print debugging message
  171.             JMPS    $cpu_ndptst          ; skip message text
  172. $dbg1       DB      'About to perform CPU and NDP test', 0Dh, 0Ah ,'$'
  173.  
  174. $cpu_ndptst:LDS     SI, ResultPtr        ; pointer to result struct
  175.             FNSTCW  [SaveCtrl]           ; save original NDP ctrl word
  176.             PUSH    SP                   ; test updating
  177.             POP     AX                   ;  of stackpointer
  178.             CMP     AX, SP               ; stackpointer updated before push ?
  179.             JES     $286_386             ; no, must be 286, 386 or 486
  180.             MOV     AX, 1                ; try to shift
  181.             MOV     CL, 33               ;  accu 33 times
  182.             SHL     AX, CL               ; shift count masked off ?
  183.             JNZS    $186_188             ; yes, must be 186 or 188
  184.             PUSHA                        ; PUSHA executed on 88/86 as JMP $+2
  185.             STC                          ; carry set if V20 or V30
  186.             JCS     $V20_V30             ; yes, must be V20 or V30
  187.             PUSHF                        ; save flags
  188.             POP     AX                   ; pop flags into AX
  189.             AND     AH, 00FH             ; clear bits 12-15 of flag register
  190.             PUSH    AX                   ; put new flags in stack
  191.             POPF                         ; pop into flag register
  192.             PUSHF                        ; put flags on stack
  193.             POP     AX                   ; get flags
  194.             AND     AH, 0F0H             ; test if all bits
  195.             CMP     AH, 0F0H             ;  in highest nibble set
  196.             JES     $88_86               ; all bits in highest nibble set
  197.             XOR     DL, DL               ; failed all tests, unknown CPU
  198.             JMPS    $copro_test          ; go and test NDP
  199. $88_86:     MOV     DL, cpu_i8088        ; else it's an 88 or 86
  200.             JMPS    $queue_test          ; decide wether 88 or 86
  201. $V20_V30:   POPA                         ; remove pushed bytes
  202.             MOV     DL, cpu_V20          ; it's an V20 or V30
  203.             JMPS    $queue_test          ; decide wether V20 or V30
  204. $186_188:   MOV     DL, cpu_i188         ; 188/186
  205. $queue_test:LEA     BX, [$patch]         ; load patch address into BX
  206.             MOV     BYTE PTR CS:[BX], 42h; preset with opcode for INC DX
  207.             MOV     AL, 90H              ; patch in a NOP (opcode 90h)
  208.             MOV     CL, 31               ; rotate register 31 times to use up
  209.             ROL     AH, CL               ;  time so prefetch queue can be filled
  210.             MOV     BYTE PTR CS:[BX], AL ; insert NOP at label $patch
  211.             NOP                          ; fill
  212.             NOP                          ;  prefetch
  213.             NOP                          ;   queue
  214.             NOP                          ;    with NOPs
  215. $patch:     INC     DX                   ; patched to NOP on i88, i188 and V20
  216. $copro_test:JMP     $ndp_test            ; check for coprocessor
  217. $286_386:   MOV     DL, cpu_i286         ; 286, 386 or 486
  218.             PUSH    7000h                ;  try to set
  219.             POPF                         ;   IOPL and NT fields
  220.             PUSHF                        ;    in bit 12-14
  221.             POP     AX                   ;     of flag register
  222.             TEST    AX, 7000h            ; bits cannot be set in 286 real mode
  223.             JZS     $copro_test          ; bits not set --> 286
  224.             INC     DX                   ; CPU is an 386 (DL = 8) or 486
  225.             MOV     EBX, ESP             ; save current stackpointer to align it
  226.             AND     ESP, 0FFFFFFFCh      ; align stack to avoid AC fault
  227.             PUSHFD                       ; save EFLAGS
  228.             POP     EAX                  ; get EFLAGS from stack
  229.             MOV     ECX, EAX             ; original value of EFLAGS
  230.             XOR     EAX, 40000H          ; toggle AC bit in EFLAGS
  231.             PUSH    EAX                  ; copy new value
  232.             POPFD                        ;  to EFLAGS
  233.             PUSHFD                       ; get new EFLAGS value
  234.             POP     EAX                  ; put into EAX
  235.             XOR     EAX, ECX             ; test if AC bit could be changed
  236.             PUSH    ECX                  ; restore original
  237.             POPFD                        ;  value of EFLAGS
  238.             MOV     ESP, EBX             ; restore original stack pointer
  239.             OR      EAX, EAX             ; EAX = 0 on 386, 40000h on 486
  240.             JNZS    $486_486dlc          ; if <> 0, must be 486/486dlc/Pentium
  241. $chk_38600: PUSH    DX                   ; save CPU code
  242.             MOV     ESI, 32              ; 32 trials to check for POPAD bug
  243.             MOV     EAX, 12345678        ; load some value
  244. $trial_loop:MOV     EBX, EAX             ; save value for comparison
  245.             MOV     EDX, 0               ; prepare index and
  246.             MOV     EDI, 0               ;  base register to point to DS:0
  247.             PUSHAD                       ; push all 32-bit registers
  248.             POPAD                        ; pop all 32-bit registers
  249.             MOV     ECX, [EDX+EDI]       ; mem access changes EAX (POPAD bug!)
  250.             CMP     EAX, EBX             ; EAX changed ?
  251.             JNZS    $changed             ; EAX changed -> bug in AMD/Intel 386
  252.             ROL     EAX, 1               ; try next number
  253.             DEC     ESI                  ; decrement trial counter
  254.             JNZS    $trial_loop          ; until 32 trials thru, exits with Z=1
  255. $changed:   POP     DX                   ; restore CPU code
  256.             JNZS    $copro_test          ; EAX changed, must be Intel/AMD 386
  257.             MOV     DL, cpu_ct38600      ; C&T 38600 doesn't have that bug
  258.             JMPS    $copro_test          ; now test for coprocessor
  259. $486_486dlc:PUSHFD                       ; check for Pentium
  260.             POP     EAX                  ; save old value of EFLAGS
  261.             MOV     ECX, EAX             ; save it in ECX
  262.             XOR     EAX, 00200000h       ; toggle ID bit
  263.             PUSH    EAX                  ; move changed value
  264.             POPFD                        ;  back to EFLAGS
  265.             PUSHFD                       ; save new EFLAGS
  266.             POP     EAX                  ;  and move it to EAX
  267.             XOR     EAX, ECX             ; old EFLAGS <> new EFLAGS ?
  268.             JZS     $chek_cyrix          ; ID bit can't be toggled -> no Pentium
  269.             JMP     $pentium             ; ID bit can be toggled -> Pentium
  270. $chek_cyrix:XOR     AX, AX               ; now check for Cyrix: define flags
  271.             PUSHF                        ; save defined flags state
  272.             PUSH    DX                   ; save CPU/NDP code
  273.             MOV     DX, 0                ; prepare division
  274.             MOV     AX, 0FFFFh           ; divide FFFF by 4
  275.             MOV     BX, 4                ; load divisor
  276.             DIV     BX                   ; do division (Cyrix doesn't touch
  277.             PUSHF                        ;  OF,SF,ZF,AF,PF,CF, but Intel does)
  278.             POP     BX                   ; get flags after division
  279.             POP     DX                   ; restore CPU/NDP code
  280.             POP     CX                   ; get flags before division
  281.             MOV     AX, 08D5h            ; mask for OF,SF,ZF,AF,PF,CF
  282.             AND     CX, AX               ; mask out bits in new flags
  283.             AND     BX, AX               ; mask out bits in old flags
  284.             CMP     CX, BX               ; compare old and new flags
  285.             MOV     DL, cpu_i486         ; default: it's a 486 (CPU = 15)
  286.             JNES    $ndp_test            ; flags are not identical -> Intel 486
  287. $cyrix_cpu: MOV     DL, cpu_486dlc       ; no, flags not changed-> 486DLC/486SLC
  288.             JMPS    $ndp_test            ; continue with NDP test
  289. $pentium:   MOV     DL, cpu_pentium      ; default: CPU is Pentium
  290.             MOV     EAX, 1               ; get CPU information
  291.             PUSH    EDX                  ; save CPU info
  292.             CPUID                        ;  from CPUID
  293.             POP     EDX                  ; restore CPU info
  294.             AND     AX, 0FF0h            ; mask out family and model fields
  295.             CMP     AX, 0480h            ; is it IntelDX4?
  296.             JNES    $ovrdrv_tst          ; no, Pentium or OverDrive
  297.             MOV     DL, cpu_iDX4         ; yes IntelDX4
  298.             JMPS    $ndp_test            ; now check math coprocessor
  299. $ovrdrv_tst:CMP     AX, 0430h            ; is it Overdrive processor?
  300.             JNES    $ndp_test            ; no, it's a Pentium CPU
  301.             MOV     DL, cpu_ovrdrv       ; it is an Overdrive processor
  302. $ndp_test:  XOR     DH, DH               ; assume no coprocessor
  303.             XOR     AX, AX               ; clear register
  304.             OUT     0F0h, AL             ; clear error signal of coprocessor
  305.             FNINIT                       ; initialize coprocessor
  306.             MOV     [Ctrl], AX           ; clear status variable
  307.             NOT     AX                   ; load all 1's
  308.             MOV     [Stat], AX           ; initialize status variable to all 1's
  309.             FNSTCW  [Ctrl]               ; store NDP control word
  310.             MOV     AX, [Ctrl]           ; get control word
  311.             AND     AX, 0F3Fh            ; extract RC, PC and exception masks
  312.             CMP     AX, 033Fh            ; RC=0, PC=3, masks=3F ?
  313.             JNES    $chk_486sx           ; no -> no coprocessor present
  314.             FNSTSW  [Stat]               ; store NDP status
  315.             TEST    WORD PTR [Stat],383Fh; stack top & exceptions must be clear
  316.             JNZS    $chk_486sx           ; ST & exceptions not clear -> no NDP
  317.             MOV     DH, ndp_Emul         ; coprocessor is at least emulator (=1)
  318.             CMP     DL, cpu_i286         ; is CPU 80286 or higher ?
  319.             JBS     $no_emulat           ; no, emulation impossible
  320.             SMSW    AX                   ; get machine status word
  321.             TEST    AL, 4                ; test if EM bit of MSW set
  322.             JZS     $no_emulat           ; not set -> no NDP emulation
  323. $chk_486sx: CMP     DL, cpu_i486         ; CPU = Intel 486 and no/emulated copro ?
  324.             SBB     DL, -1               ; yes, CPU is 486sx (increment DL)
  325.             JMP     $ndp_exit            ; no further NDP checking
  326. $no_emulat: MOV     DH, ndp_i8087        ; coprocessor is at least 8087 (=2)
  327.             FLD1                         ; load 1.0
  328.             WAIT                         ; needed for 8087
  329.             FLDZ                         ; load 0.0
  330.             WAIT                         ; needed for 8087
  331.             FDIV                         ; 1.0 / 0.0 = +infinity
  332.             WAIT                         ; needed for 8087
  333.             FLD     ST(0)                ; duplicate +infinity
  334.             WAIT                         ; needed for 8087
  335.             FCHS                         ; generate -infinity
  336.             WAIT                         ; needed for 8087
  337.             FCOMPP                       ; compare infinities and clear NDP stk
  338.             WAIT                         ; needed for 8087
  339.             FSTSW   WORD PTR [Stat]      ; save condition codes
  340.             MOV     AX, [Stat]           ; load condition codes
  341.             SAHF                         ; transfer into CPU flags
  342.             JNES    $187_387             ; 187, C287 or 387 if numbers not equal
  343.             CMP     DL, cpu_i286         ; is CPU >= 286 ?
  344.             JBS     $ndp_exit1           ; no, coprocessor is 8087
  345.             MOV     DH, ndp_i80287       ; coprocessor is 287
  346.             JMPS    $chk_iit             ; check for IIT coprocessors
  347. $187_387:   CMP     DL, cpu_i286         ; is CPU >= 286 ?
  348.             JAES    $C287_387            ; yes, NDP is either C287, 287XL or 387
  349.             MOV     DH, ndp_i80C187      ; coprocessor is 187
  350.             JMPS    $ndp_exit1           ; store CPU and NDP code
  351. $C287_387:  CMP     DL, cpu_i386         ; is CPU >= 386 ?
  352.             JAES    $387_486             ; yes, NDP is 387 or 387sx, 486
  353.             MOV     DH, ndp_i287XL       ; coprocessor is C287
  354.             JMPS    $chk_iit             ; check for IIT coprocessors
  355. $387_486:   CMP     DL, cpu_i486         ; is CPU >= 486 ?
  356.             JAES    $i486                ; yes, NDP is 486 / 487
  357.             MOV     DH, ndp_i387         ; coprocessor is 387 or 387sx
  358.             JMPS    $chk_iit             ; check for IIT coprocessors
  359. $i486:      CMP     DL, cpu_pentium      ; is CPU Intel Pentium ?
  360.             JES     $ipentium            ; yes, FPU is also Pentium
  361.             CMP     DL, cpu_iDX4         ; is CPU Intel DX4 ?
  362.             JES     $iDX4                ; yes, FPU is also Intel DX4
  363.             CMP     DL, cpu_ovrdrv       ; is CPU Intel OverDrive ?
  364.             JES     $iovrdrv             ; yes, FPU is also Intel OverDrive
  365.             MOV     DH, ndp_i486         ; NDP = 486 / 487
  366.             JMPS    $ndp_exit1           ; done with FPU detection
  367. $iovrdrv:   MOV     DH, ndp_ovrdrv       ; NDP = Intel OverDrive
  368.             JMPS    $ndp_exit1           ; done with FPU detection
  369. $iDX4:      MOV     DH, ndp_iDX4         ; NDP = DX4
  370.             JMPS    $ndp_exit1           ; done with FPU detection
  371. $ipentium:  MOV     DH, ndp_pentium      ; set FPU type = Pentium
  372. $ndp_exit1: JMP     $ndp_exit            ; no further tests required
  373. $chk_iit:   FNINIT                       ; initialize coprocessor
  374.             FLD     CS:[$denormal]       ; load denormal number
  375.             FADD    ST(0), ST            ; result is zero on IIT
  376.             FNSTSW  AX                   ; get status of NDP into AX
  377.             TEST    AL, 02h              ; test if denormal exception flag set
  378.             JNZS    $chk_ulsi            ; Intel NDPs signal denormal exception
  379.             ADD     DH,ndp_2c87-ndp_i80287;set IIT coprocessor types
  380.             JMPS    $ndp_exit1           ; coprocessor type found
  381. $chk_ulsi:  CMP     DL, cpu_i386         ; CPU >= 386 ?
  382.             JBS     $chk_cyrix1          ; no, can not be ULSI
  383.             FNINIT                       ; initialize coprocessor
  384.             FLDCW   CS:[$53bit_prec]     ; PC => 53 bits (ULSI ignores PC)
  385.             FLD     TBYTE PTR CS:[$op1]  ; load 2-epsilon
  386.             FLD1                         ; load 1
  387.             FADDP   ST(1), ST            ; result should be 3 and PE raised
  388.             FSTP    TBYTE PTR [GDT]      ; store result, clear NDP stack
  389.             FNSTSW  AX                   ; get coprocessor status word
  390.             TEST    AL, 20h              ; precision exception ?
  391.             JNZS    $chk_cyrix1          ; ULSI computes 64 bit result, no PE!
  392.             FWAIT                        ; make sure result is stored
  393.             CMP     BYTE PTR [GDT], 0F8h ; check least significant mantissa bits
  394.             JNES    $chk_cyrix1          ; not expected result for ULSI
  395.             CMP     BYTE PTR [GDT+9], 40h; check exponent hi-byte
  396.             JNES    $chk_cyrix1          ; not expected result for ULSI
  397.             ADD     DH,ndp_83C87-ndp_i387; set ULSI types
  398.             JMPS    $ndp_exit1           ; done
  399. $chk_cyrix1:FNINIT                       ; initialize coprocessor
  400.             FLD     TBYTE PTR CS:[$nan]  ; load positive NaN
  401.             FLD     ST(0)                ; duplicate NaN
  402.             FCHS                         ; make negative NaN
  403.             FPATAN                       ; ATAN (-NaN, +NaN) should return +NaN
  404.             FSTP    TBYTE PTR [GDT]      ; store result, clear NDP stack
  405.             FWAIT                        ; wait until result is stored
  406.             CMP     BYTE PTR [GDT+9], 7Fh; Cyrix ret. +NAN (7F),Intel -NAN (FF)
  407.             JNES    $chk_ct              ; Intel coprocessor
  408. $chk_emc87: FNSTCW  [Ctrl]               ; store control word
  409.             OR      BYTE PTR [Ctrl+1],80h; set msb of control word
  410.             FLDCW   [Ctrl]               ; and load back into coprocessor
  411.             FSTCW   [Ctrl]               ; store control word again
  412.             FWAIT                        ; wait until stored
  413.             TEST    BYTE PTR [Ctrl+1],80h; could msb be set ?
  414.             JZS     $no_emc              ; no -> no EMC87
  415.             MOV     DH, ndp_emc87        ; set NDP type to EMC87
  416.             JMPS    $ndp_exit            ; done
  417. $no_emc:    ADD     DH,ndp_82S87-ndp_i80287; set old Cyrix types
  418.             FLD1                         ; load 1.0
  419.             FLD     ST(0)                ; load another 1.0
  420.             FYL2XP1                      ; compute 1.0*ld(2.0)
  421.             FLD1                         ; compare result with 1.0
  422.             FCOMPP                       ; new Cyrix copros have correct result
  423.             FNSTSW  AX                   ; store coprocessor condition bits
  424.             SAHF                         ; transfer to CPU flags
  425.             JNES    $ndp_exit            ; if incorrect result, not new Cyrix
  426.             ADD     DH,ndp_82S87p-ndp_82S87; set NDP-type to new Cyrix types
  427.             JMPS    $ndp_exit            ; done
  428. $chk_ct:    CMP     DL, cpu_i386         ; CPU >= 386 ?
  429.             JBS     $chk_387DX           ; no, can not be C&T
  430.             FNINIT                       ; initialize coprocessor
  431.             FLDPI                        ; load pi
  432.             F2XM1                        ; 2**(pi)-1=pi/2, argument out of range
  433.             FLD1                         ; load 1.0
  434.             FCHS                         ; -1.0
  435.             FLDPI                        ; load pi
  436.             FSCALE                       ; pi/2
  437.             FSTP    ST(1)                ; pi/2
  438.             FCOMPP                       ; 2**(pi)-1=pi/2 ?
  439.             FSTSW   AX                   ; save condition codes
  440.             SAHF                         ; transfer to CPU flags
  441.             JNES    $chk_387DX           ; not equal, not C&T
  442.             ADD     DH,ndp_38700-ndp_i387; set C&T types
  443.             JMPS    $ndp_exit            ; done
  444. $chk_387DX: CMP     DH, ndp_i387         ; Intel 387 ?
  445.             JNES    $ndp_exit            ; no, done. Only want to check i387
  446.             FNINIT                       ; initialize coprocessor
  447.             FLD1                         ; load 1.0
  448.             FCHS                         ; -1.0
  449.             FXTRACT                      ; split into mantissa and exponent(0)
  450.             FSTP    ST(0)                ; pop mantissa
  451.             FXAM                         ; look at sign of exponent
  452.             FNSTSW  AX                   ; store status word
  453.             AND     AH, 2                ; C1 set (negative) on old 387
  454.             FSTP    ST(0)                ; clear coprocessor stack
  455.             JNZS    $ndp_exit            ; C1 set, no 387DX
  456.             MOV     DH, ndp_i387DX       ; set NDP-type to 387DX
  457.             FNINIT                       ; initialize coprocessor
  458.             FBSTP   TBYTE PTR [GDT]      ; store BCD indefinite
  459.             CMP     BYTE PTR [GDT+7],0C0h; RapidCAD stores C0h, 387DX stores 80h
  460.             JNES    $ndp_exit            ; no RapidCAD
  461.             MOV     DX, ndp_RapidCAD*100H+cpu_RapidCAD; RapidCAD (NDP=21,CPU=14)
  462. $ndp_exit:  LDS     SI, ResultPtr        ; pointer to result record
  463.             MOV     [SI], DX             ; save CPU and NDP types
  464.             JMPS    $moveeven            ; skip over test data for NDP check
  465.  
  466. $denormal   DT      1
  467. $nan        DB      0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 07Fh
  468. $op1        DB      0F0h, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 03Fh
  469. $53bit_prec DW      027Fh
  470.  
  471.  
  472. $moveeven:  CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  473.             JNZS    $moveeven1           ; no
  474.             MOV     AH, 9                ; #9, print string
  475.             PUSH    CS                   ; load
  476.             POP     DS                   ;  address of
  477.             MOV     DX, OFFSET CS:$dbg3  ;   debugging message
  478.             INT     21h                  ; call DOS, print debugging message
  479.             JMPS    $moveeven1           ; skip message text
  480. $dbg3       DB      'About to perform MOVEEVEN memory speed test', 0Dh, 0Ah ,'$'
  481.  
  482. $moveeven1: MOV     AX, DS               ; set up segment registers
  483.             MOV     ES, AX               ;  for memory move
  484.             XOR     SI, SI               ; offset in both segments
  485.             MOV     DI, SI               ;  is zero
  486.             MOV     CX, 5000             ; move 5000
  487.             REP     MOVSW                ;  words
  488.             STRT_TIM                     ; start timer 2
  489.             XOR     SI, SI               ; offset in both segments
  490.             MOV     DI, SI               ;  is zero
  491.             MOV     CX, 5000             ; move 5000
  492.             REP     MOVSW                ;  words
  493.             STOP_TIM                     ; elapsed time of timer 2 in BX
  494.             LDS     SI, ResultPtr        ; pointer to result record
  495.             MOV     [SI+6], BX           ; save MoveEvenTime
  496.  
  497.  
  498. $movebyte:  CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  499.             JNZS    $movebyte1           ; no
  500.             MOV     AH, 9                ; #9, print string
  501.             PUSH    CS                   ; load
  502.             POP     DS                   ;  address of
  503.             MOV     DX, OFFSET CS:$dbg5  ;   debugging message
  504.             INT     21h                  ; call DOS, print debugging message
  505.             JMPS    $movebyte1           ; skip message text
  506. $dbg5       DB      'About to perform MOVEBYTE wait state test', 0Dh, 0Ah ,'$'
  507.  
  508. $movebyte1: MOV     AX, DS               ; set up segment registers
  509.             MOV     ES, AX               ;  for memory move
  510.             MOV     SI, 1                ; offset in source and destination
  511.             MOV     DI, SI               ;  segment is odd
  512.             STRT_TIM                     ; start timer 2
  513.             MOV     CX, 5000             ; move 5000
  514.             REP     MOVSB                ;  bytes
  515.             STOP_TIM                     ; elapsed time of timer 2 in BX
  516.             LDS     SI, ResultPtr        ; pointer to result struct
  517.             MOV     [SI+10], BX          ; save MoveByteTime
  518.  
  519. $movedouble:CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  520.             JNZS    $movedoubl1          ; no
  521.             MOV     AH, 9                ; #9, print string
  522.             PUSH    CS                   ; load
  523.             POP     DS                   ;  address of
  524.             MOV     DX, OFFSET CS:$dbg6  ;   debugging message
  525.             INT     21h                  ; call DOS, print debugging message
  526.             JMPS    $movedoubl1          ; skip message text
  527. $dbg6       DB      'About to perform MOVEDOUBLE 386sx test', 0Dh, 0Ah ,'$'
  528.  
  529. $movedoubl1:LDS     SI, ResultPtr        ; pointer to result struct
  530.             CMP     BYTE PTR [SI],cpu_i386; CPU = iAPX 386 or i486 ?
  531.             JBS     $move_ems            ; no 386/486
  532.             MOV     AX, DS               ; load segment registers
  533.             MOV     ES, AX               ;  for memory move
  534.             XOR     SI, SI               ; offset in source and destination
  535.             MOV     DI, SI               ;  segment is 0
  536.             MOV     CX, 5000             ; move 5000
  537.             REP     MOVSD                ;  double words
  538.             STRT_TIM                     ; start timer 2
  539.             XOR     SI, SI               ; offset in source and destination
  540.             MOV     DI, SI               ;  segment is 0
  541.             MOV     CX, 5000             ; move 5000
  542.             REP     MOVSD                ;  double words
  543.             STOP_TIM                     ; elapsed time for 2 in BX
  544.             LDS     SI, ResultPtr        ; pointer to result struct
  545.             MOV     [SI+24], BX          ; save MoveDouble-Time
  546.  
  547. $chk_386sx: CMP     BYTE PTR [SI], cpu_i486 ; CPU >= i486 ?
  548.             JAES    $move_ems            ; yes, no need to test for 386sx
  549.             MOV     AX, [SI+6]           ; AX = MoveWord-Time
  550.  
  551.             XCHG    AX, BX               ; AX = MoveDouble-Time,BX=MoveWord-Time
  552.             SUB     AX, BX               ; MoveDTime - MoveWTime
  553.             ADD     AX, AX               ; 2 * (MoveDTime - MoveWTime)
  554.             CWD                          ; compute
  555.             XOR     AX, DX               ;  Abs (2 * (MoveDoubleTime -
  556.             SUB     AX, DX               ;   MoveWordTime))
  557.             CMP     BX, AX               ; Abs(2*(MoveDTime-MoveWTime))>MoveWTime ?
  558.             ADC     WORD PTR [SI], 0     ; CPU type = 386sx if true
  559.             CMP     BYTE PTR [SI],cpu_ct38600sx; CPU = C&T 38600sx ?
  560.             JNES    $move_ems            ; no
  561.             MOV     BYTE PTR [SI],cpu_i386sx; POPAD test unreliable for 386sx,
  562.                                          ; reset to Intel 386 since more likely
  563.  
  564. $move_ems:  CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  565.             JNZS    $move_ems1           ; no
  566.             MOV     AH, 9                ; #9, print string
  567.             PUSH    CS                   ; load
  568.             POP     DS                   ;  address of
  569.             MOV     DX, OFFSET CS:$dbg7  ;   debugging message
  570.             INT     21h                  ; call DOS, print debugging message
  571.             JMPS    $move_ems1           ; skip message text
  572. $dbg7       DB      'About to perform EMS memory access test', 0Dh, 0Ah ,'$'
  573.  
  574. $move_ems1: CMP     BYTE PTR EMS_Flag, 0 ; does EMS memory exist ?
  575.             JES     $move_ext            ; no, skip this test
  576.             MOV     AH, 43h              ; #43, allocate page
  577.             MOV     BX, 1                ;  one page
  578.             INT     67h                  ; call EMM-driver (handle in DX)
  579.             MOV     AH, 47h              ; #47, save page map
  580.             INT     67h                  ; call EMM-driver
  581.             MOV     AH, 44h              ; #44, map page
  582.             MOV     AL, 0                ; physical page 0
  583.             MOV     BX, 0                ; logical page 0
  584.             INT     67h                  ; call EMM-driver
  585.             LES     DI, BufferPtr        ; pointer to buffer
  586.             MOV     CX, 5000             ; 5000 words
  587.             LDS     SI, ResultPtr        ; pointer to result struct
  588.             STRT_TIM                     ; start timer 2
  589.             CMP     BYTE PTR [SI], cpu_i386 ; processor 386 or higher?
  590.             LDS     SI, EMS_Base         ; pointer to EMS page frame
  591.             JAES    $is_386              ; is a 386/486
  592.             REP     MOVSW                ; move words from page frame to buffer
  593.             JMPS    $no_386              ; was no 386/486
  594. $is_386:    MOV     CX, 4000             ; 4000 double words = 1 EMS page
  595.             REP     MOVSD                ; move 4000 double words
  596. $no_386:    STOP_TIM                     ; elapsed time of timer 2 in BX
  597.             LDS     SI, ResultPtr        ; pointer to result struct
  598.             MOV     [SI+12], BX          ; save MoveEMSTime
  599.             MOV     AH, 48h              ; #48, restore map
  600.             INT     67h                  ; call EMM-driver
  601.             MOV     AH, 45h              ; #45, deallocate page
  602.             INT     67h                  ; call EMM-driver
  603.  
  604. $move_ext:  CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  605.             JNZS    $move_ext1           ; no
  606.             MOV     AH, 9                ; #9, print string
  607.             PUSH    CS                   ; load
  608.             POP     DS                   ;  address of
  609.             MOV     DX, OFFSET CS:$dbg8  ;   debugging message
  610.             INT     21h                  ; call DOS, print debugging output
  611.             JMPS    $move_ext1           ; skip message text
  612. $dbg8       DB      'About to perform extended memory access test', 0Dh, 0Ah ,'$'
  613.  
  614. $move_ext1: CMP     BYTE PTR Ext_Flag, 0 ; does extended memory exist ?
  615.             JES     $screenfill          ; no, skip test
  616.             STRT_TIM                     ; start timer 2
  617.             XOR     AX, AX               ; load zero
  618.             MOV     BX, SS               ; load
  619.             MOV     ES, BX               ;  address
  620.             LEA     DI, GDT              ;   of GDT
  621.             MOV     CX, 30h              ; 30h bytes long
  622.             REP     STOSB                ; init with 0
  623.             LEA     SI, GDT              ; reload address of GDT
  624.             MOV     WORD PTR GDT+10H,10000; number of bytes to move
  625.             MOV     WORD PTR GDT+12H, 0  ; source:
  626.             MOV     BYTE PTR GDT+14H, 10H;  100000H (start of extended memory)
  627.             MOV     BYTE PTR GDT+15H, 93H; access rights (read/write)
  628.             MOV     WORD PTR GDT+18H,10000; number of bytes to move
  629.             LDS     DI, BufferPtr        ; load pointer to buffer
  630.             MOV     AX, DS               ; load pointer into DX:AX
  631.             XOR     DX, DX               ; linearize
  632.             SHL     AX, 1                ;  address,
  633.             RCL     DX, 1                ;   32 bit result
  634.             SHL     AX, 1                ;    in
  635.             RCL     DX, 1                ;     DX:AX
  636.             SHL     AX, 1                ;
  637.             RCL     DX, 1                ;
  638.             SHL     AX, 1                ;
  639.             RCL     DX, 1                ;
  640.             ADD     AX, DI               ;
  641.             ADC     DX, 0                ;
  642.             MOV     WORD PTR GDT+1AH, AX ; destination:
  643.             MOV     BYTE PTR GDT+1CH, DL ;  buffer
  644.             MOV     BYTE PTR GDT+1DH, 93H; access rights (read/write)
  645.             MOV     AH, 87h              ; move from extended memory
  646.             MOV     CX, 5000             ; move 5000 words from ext to buffer
  647.             INT     15H                  ; call AT-BIOS
  648.             STOP_TIM                     ; elapsed time of timer 2 in BX
  649.             LDS     SI, ResultPtr        ; pointer to result record
  650.             MOV     [SI+14], BX          ; save MoveExtTime
  651.  
  652. $screenfill:CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  653.             JNZS    $screenfil1          ; no
  654.             MOV     AH, 9                ; #9, print string
  655.             PUSH    CS                   ; load
  656.             POP     DS                   ;  address of
  657.             MOV     DX, OFFSET CS:$dbg9  ;   debugging message
  658.             INT     21h                  ; call DOS, print string
  659.             JMPS    $screenfil1          ; skip message text
  660. $dbg9       DB      'About to perform SCREENFILL test', 0Dh, 0Ah ,'$'
  661.  
  662. $screenfil1:LES     DI, ScreenPtr        ; pointer to start of video memory
  663.             STRT_TIM                     ; start timer 2
  664.             MOV     CX, 5000             ; fill 5000 bytes
  665.             REP     STOSB                ;  of video memory
  666.             STOP_TIM                     ; elapsed time for timer 2 in BX
  667.             LDS     SI, ResultPtr        ; pointer to result struct
  668.             MOV     [SI+16], BX          ; save ScreenFillTime
  669.  
  670. $bios_write:CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  671.             JNZS    $bios_writ1          ; no
  672.             MOV     AH, 9                ; #9, print string
  673.             PUSH    CS                   ; load
  674.             POP     DS                   ;  address of
  675.             MOV     DX, OFFSET CS:$dbg4  ;   debugging message
  676.             INT     21h                  ; call DOS, print debugging message
  677.             JMPS    $bios_writ1          ; skip message text
  678. $dbg4       DB      'About to perform BIOS_WRITE screen speed test', 0Dh, 0Ah ,'$'
  679.  
  680. $bios_writ1:STRT_TIM                     ; start timer 2
  681.             MOV     SI, 20               ; write 20 characters
  682. $out_loop:  MOV     AX, 0920h            ; #9, write char and attribute
  683.             MOV     BX, 0                ; page 0, attribute = blank
  684.             MOV     CX, 1                ; write one character at a time
  685.             INT     10H                  ; call video-BIOS
  686.             DEC     SI                   ; loop over number of chars
  687.             JNZS    $out_loop            ; until all 20 chars output
  688.             STOP_TIM                     ; elapsed time of timer 2 in BX
  689.             LDS     SI, ResultPtr        ; pointer to result struct
  690.             MOV     [SI+8], BX           ; save BIOS-WriteTime
  691.  
  692. $speed87:   CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  693.             JNZS    $speed871            ; no
  694.             MOV     AH, 9                ; #9, print string
  695.             PUSH    CS                   ; load
  696.             POP     DS                   ;  address of
  697.             MOV     DX, OFFSET CS:$dbg10 ;   debugging message
  698.             INT     21h                  ; call DOS, print debugging message
  699.             JMPS    $speed871            ; skip message text
  700. $dbg10      DB      'About to perform NDP speed test', 0Dh, 0Ah ,'$'
  701.  
  702. $speed871:  LDS     SI, ResultPtr        ; pointer to result struct
  703.             CMP     BYTE PTR [SI+1], 1   ; real coprocessor present ?
  704.             JAS     $cont_87             ; yes, do coprocessor tests
  705.             JMP     $no_fpu              ; no, done
  706. $cont_87:   WAIT                         ; for 8087
  707.             FNINIT                       ; initialize coprocessor
  708.             WAIT                         ; for 8087
  709.             FLD1                         ; load 1
  710.             STRT_TIM                     ; start timer 2
  711.             REPT    40                   ; do following 40 times:
  712.             WAIT                         ;  needed on 8087
  713.             FSQRT                        ;  compute Sqrt(1)
  714.             ENDM
  715.             FWAIT                        ; wait until coprocessor done
  716.             STOP_TIM                     ; time for 40 sqrt computations on BX
  717.             LDS     SI, ResultPtr        ; pointer to result struct
  718.             MOV     [SI+20], BX          ; save 87-Time
  719.  
  720. $speed287:  FNINIT                       ; initialize coprocessor
  721.             FLD1                         ; load 1
  722.             STRT_TIM                     ; start timer 2
  723.             REPT    40                   ; do following 40 times:
  724.             NOP                          ;  needed on 8087
  725.             FSQRT                        ;  compute Sqrt(1)
  726.             ENDM
  727.             STOP_TIM                     ; time for 40 sqrt computations in BX
  728.             LDS     SI, ResultPtr        ; pointer to result struct
  729.             MOV     [i287Time], BX       ; save 287-Time
  730.             MOV     CX, [SI]             ; get CPU (CL) and NDP (CH)
  731. $chk_387sx: CMP     CL, cpu_i386sx       ; CPU = 80386sx ?
  732.             JES     $has_387sx           ; is SX
  733.             CMP     CL, cpu_ct38600sx    ; CPU = 38600sx ?
  734.             JES     $has_387sx           ; is SX
  735.             CMP     CL, cpu_486slc       ; CPU = 486SLC ?
  736.             JNES    $no_387sx            ; no SX
  737. $has_387sx: INC     CH                   ; set SX versions of 387 coprocessors
  738. $no_387sx:
  739. $store_type:MOV     [SI], CX             ; save CPU and NDP type
  740.             CMP     CL, cpu_i286         ; CPU higher than 286 ?
  741.             JBES    $no_weitek           ; no, Weitek only available for 386/486
  742.             PUSH    SI                   ; save pointer
  743.             PUSH    DS                   ;  to result struct
  744.             XOR     EAX, EAX             ; zero everything in result register
  745.             INT     11h                  ; do equipment check
  746.             TEST    EAX, 01000000h       ; check bit 24, set if Weitek present
  747.             POP     DS                   ; restore pointer
  748.             POP     SI                   ;  to result struct
  749.             JES     $no_weitek           ; bit not set, no Weitek
  750.             OR      BYTE PTR [SI+1], 80h ; set Weitek flag in coprocessor type
  751. $no_weitek: FNINIT                       ; reprogram
  752.             FLDCW   [SaveCtrl]           ;  original NDP control word
  753.  
  754. $no_fpu:    MOV     AL, [SystemStat]     ; get original system status
  755.             OUT     61h, AL              ;  and restore it
  756.  
  757. $ende:      POPF                         ; restore original flag settings
  758.             POP     DS                   ; restore Turbo Pascal's data segment
  759.             MOV     SP, BP               ; discard local variables
  760.             POP     BP                   ; restore caller's frame pointer
  761.             RET     22                   ; return, pop parameters
  762.  
  763. COMMENT #
  764.             MOV     EAX, 0417A000h       ; test if early 80386
  765.             MOV     ECX, 00000081h       ;  processor with 32 multiplication bug
  766.             MUL     ECX
  767.             CMP     EDX, 00000002h
  768.             JNZS    $mul_err
  769.             CMP     EAX, 0FE7A000h
  770.             JNZS    $mul_err
  771. #
  772.  
  773. SpeedTest   ENDP
  774.  
  775.  
  776. CODE        ENDS
  777.  
  778.             END
  779.